#ifndef xpack_lang_cxx_private_parse_base64x
#define xpack_lang_cxx_private_parse_base64x
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::lang_cxx::inc
#include"define/base_type.hpp"
#include"lang/cxx/private/lut.base64x.hpp"
#include"lang/cxx.hpp"
#include"macro/xexport.hpp"
#include"macro/xunlikely.hpp"
#include"meta/remove_ref.hpp"
#include"meta/unsigned_type.hpp"
#pragma pop_macro("xuser")

namespace mixc::lang_cxx{
    template<class item_t>
    inline auto parse_base64x(cxx<item_t> const & self, cu08p lut, auto const & alloc){
        using seq_t                 = decltype(alloc(0));
        using result_t              = parse_base64_result<seq_t>;
        using u_t                   = inc::unsigned_type<item_t>;
        using buffer_item_t         = inc::remove_ref<decltype(alloc(0)[0])>;
        auto skip                   = uxx(0);
        auto cxx_len                = uxx(self->length);
        auto len                    = cxx_len;

        while(len-- > 0){
            if (self[len] != '='){
                break;
            }
            else{
                skip               += 1;
            }
        }

        auto origin_str             = self.shorten(skip);
        auto real_length            = uxx(origin_str->length);
        auto total_length           = real_length * 3 / 4;
        auto buffer                 = alloc(total_length);

        xunlikely(buffer == nullptr){
            return result_t{};
        }

        auto i                      = uxx(0);
        auto ii                     = uxx(0);
        auto temp                   = u32(0);

        for(; i + 4 <= real_length; i += 4){
            for(uxx j = 0, k = i;; j++, k++){
                if (j == 4){
                    // buffer_item_t 不一定是 1 个字节，也不一定是无符号数
                    buffer[ii++]    = buffer_item_t(u08(temp >> 16));
                    buffer[ii++]    = buffer_item_t(u08(temp >>  8));
                    buffer[ii++]    = buffer_item_t(u08(temp >>  0));
                    break;
                }

                xunlikely(auto index = u_t(self[k]); index >= 256){
                    return result_t(buffer, k);
                }
                else xunlikely(u08 bits = lut[index]; bits == 0xff){
                    return result_t(buffer, k);
                }
                else{
                    temp            = temp << 6 | bits;
                }
            }
        }

        auto shift                  = 32 - 6;
        auto rest                   = real_length - i;
        auto old_i                  = i;

        if (rest != 0){
            for(temp = 0; i < real_length; i++){
                xunlikely(auto index = u_t(self[i]); index >= 256){
                    return result_t(buffer, old_i);
                }
                else xunlikely(u08 bits = lut[u08(self[i])]; bits == 0xff){
                    return result_t(buffer, old_i);
                }
                else{
                    temp           |= u32(bits) << shift;
                    shift          -= 6;
                }
            }

            for(i = 0; i < rest; i++){
                buffer[ii++]        = buffer_item_t(u08(temp >> 24));
                temp               <<= 8;
            }
        }

        return result_t(buffer);
    }
}

#endif
